Docker 在 Kubernetes 里弃用了,怎么办?
(给Go开发大全
加星标)
英文:Kohei Ota,
翻译:Go开发大全 / 字符串拼接工程师
一、太长不看版
对开发者来说:
不慌,Docker 容器和镜像依然是要用的,并不是所有都变了。
以下两篇文章也推荐阅读:
https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/
https://kubernetes.io/blog/2020/12/02/dockershim-faq/
对于 k8s 管理员来说:
认真读一下这篇文章、要开始找 docker 之外的解决方案了。
二、弃用是真的吗?
是真的。docker 被 kubernetes 废弃了。
参考这篇 changeLog:
https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.20.md#deprecation
kubelet 中对 docker的支持被废弃、将会在未来的版本中被移除。kubelet 用了一个叫 “dockershim” 的模块,这个模块实现了 Docker 的 CRI、一直都有针对这些实现的issue 提到 kubernetes 社区里。我们鼓励您评估向可用的 CRI(v1alpha1 或 v1 兼容)的完整实现的运行时容器的迁移。
简单来说,就是 Docker 不支持 Kubernetes 的叫做 CRI(Container Runtime Interface)的运行时 API,Kubernetes 开发者一直在使用名为“dockershim”的桥接服务。它转换了Docker API 和 CRI,一些版本后将不再从 Kubernetes 层面提供支持。
docker 在本地是一个很强大的创建开发环境的工具,但是要理解是什么引起了这些,就需要理解docker在当前的kubernetes架构下干了什么。
k8s是一个基础架构调度工具,它对很多不同计算资源进行分组(如虚拟机、物理机),让这些资源卡你来像是一整个巨大的计算资源,你可以在这个大计算资源里运行服务或和其他人共用。这个架构下,通过k8s平台的控制面进行调度,可以让docker或容器运行时在机器上运行应用程序。
看上面这个架构图,每个 k8s 节点和控制平面交互。每个节点的 kubelet 获取 metadata、并通过调度 CRI,在节点上创建或删除容器。
docker为何被弃用?
kubernetes只通过CRI调度容器运行时、和docker做交互需要一个桥接服务。这是理由1。
要解释下一个理由,还要看一下docker架构。这是架构图:
k8s实际上需要红色圈圈里的部分。docker网络和docker存储卷在k8s里没有用到。
拥有实际上从来不用的功能,这就是个安全隐患。功能越少、攻击平台越少。
这就是k8s开始把CRI运行时当作其他选项的原因。
CRI 运行时
有两种主要的CRI运行时实现。
containerd
如果只是从docker迁移掉,这是最好的选择,containerized实际上是在docker内部用的,可以完成所有“运行时”工作,如上面架构图所示。它们提供CRI,这也100%和docker提供的CRI相同。
containerd是100%开源,可以在GitHub上看文档,也可以给它贡献代码。
https://github.com/containerd/containerd/
CRI-O
CRI-O是一个主要由红帽公司的人开发的CRI运行时。实际上,这个运行时被用在红帽OpenShift上。OpenShift已经不再依赖docker了。
有趣的是,RHEL 7也不再官方地支持docker了。反而为容器环境提供Podman,Buildah和CRI-O。
https://github.com/cri-o/cri-o
我认为CRI-O的长处是它很小,因为CRI-O就是作为CRI运行时开发的。不像containerd是docker的开源的一部分,CRI-O就是纯CRI运行时、没有CRI不需要的其他任何部分。
因为它的纯正、没有CRI之外的部分,让从docker迁移到CRI-O可能很有挑战性。当然CRI-O也提供了要在k8s上运行服务的所需功能。
还有一件事
当我们讨论容器运行时的时候,我们要非常小心我们在讨论什么类型的容器运行时。的确有两种运行时,即CRI运行时和OCI运行时。
CRI运行时
正如我描述的,CRI是Kubernetes提供的、与容器运行时进行通信来创建/删除容器化应用的API。
kubelet和运行时通过IPC、以gRpc的方式通信交互,CRI运行时负责从kubelet拿到请求结果后调度OCI容器运行时到一个容器里运行。看下图:
CRI运行时做了两件事:
从kubelet拿到grpc
根据这个json,创建OCI json配置:https://github.com/opencontainers/runtime-spec/blob/master/schema/config-schema.json
OCI运行时
OCI运行时负责使用Linux内核系统调用(例如cgroups和命名空间)生成容器。比如runc或gVisor。
附录1:runC如何工作
CRI通过调用Linux系统调用执行二进制文件后,runC生成容器。这表明runC依赖Linux内核。
这也意味着,如果runC的漏洞获得了root权限,容器化的应用程序也可以获得root权限。黑客可以利用这个漏洞进行攻击。这就是为什么Docker或其他容器运行时也应该被不断更新的原因之一,而不仅仅是只更新容器化的应用程序。
附录2:gVisor如何工作
gVisor是最初由Google员工创建的OCI运行时。gVisor在Google基础架构上作为云服务运行,例如Google Cloud Run,第二代Google App Engine和Google Cloud Functions等。
这里有趣的是gVisor具有“guest内核”层,这意味着容器化的应用程序无法直接接触主机内核层。即使他们认为这样做,也只能接触gVisor的guest内核。
gVisor的安全模型实际上非常有趣,值得阅读官方文档。
gVisor与runC的显着区别如下:
性能较差
Linux内核层不是100%兼容的
查看官方文档关于兼容性的部分
默认不支持
结论
Docker已经确定要废弃了,但是只是在Kubernetes废弃。如果你是k8s管理员,就要开始考虑启用其他CRI运行时了,比如containerd和CRI-O
a. containerd与Docker兼容,其中核心组件相同。
b. 如果只要k8s所需的最少功能,CRI-O是个好选择
2.了解CRI和OCI运行时职责和范围的区别
根据您的工作量,runC 可能不一定总是最佳选择。
- EOF -
如果觉得本文不错,欢迎转发推荐给更多人。
分享、点赞和在看
支持我们分享更多好文章,谢谢!